<template>
    <div class="editor" ref="root"></div>
</template>

<script lang="ts">
export * from './types'
export type { AllTheme, ThemeName } from './index/initTheme'
export { ThemeStore } from './index/initTheme'
export default {
    name: "monacoEditor",
}
</script>

<script lang="ts" setup>
import { initMonaco, initPlugin } from './index/Editor'
import { initTheme, AllTheme, applyTheme } from "./index/initTheme";
import { onMounted, ref, watch, onUnmounted, nextTick } from "vue";
import { CodeEditor, LanguageList } from './types'
import * as Monaco from "monaco-editor";
const $props = withDefaults(defineProps<{
    modelValue: string;
    language?: LanguageList;
    theme?: keyof AllTheme;
    options?: Partial<Monaco.editor.IStandaloneEditorConstructionOptions>
}>(), {
    language: 'javascript',
    theme: "github-gist",
    options: () => ({})
});

const $emit = defineEmits<{
    (event: "save", code: string): void;
    (event: "input", code: string): void;
    (event: "update:model-value", code: string): void;
    (event: "ready"): void;
}>();


const root = ref<HTMLDivElement>();

/** 只有向外更新的时候才能更新这个值，这个值给向内更新做副本检测 */
const codeCache = ref('')
let monacoEditor = null as CodeEditor | null;

onMounted(async () => {
    console.group('MonacoEditor 加载开始')
    await initTheme()
    monacoEditor = await initMonaco(root.value!, $props.modelValue, $props.language, $props.options, [initEvent, initKeybind, initAction])
    // 保证延迟加载成功
    setValue($props.modelValue)
    await applyTheme($props.theme)
    console.groupEnd()
    $emit("ready");
})



// 自动更新代码
watch(() => $props.modelValue, (val) => {
    // 保证不会循环注入
    if (val !== codeCache.value) setValue(val)
});

/** 保存代码 */
const saveValue = () => {
    if (monacoEditor === null) return;
    const code = monacoEditor!.getValue();
    codeCache.value = code
    $emit("save", code);
    $emit("input", code);
    $emit("update:model-value", code);
    console.log("MonacoEditor 保存成功");
    return code
}
/** 必须要通过这种方式改变编辑来保证贯标处于正确位置 */
const setValue = (code: string) => {
    if (monacoEditor === null) return;
    let range = monacoEditor.getModel()!.getFullModelRange();

    let op = {
        identifier: { major: 1, minor: 1 },
        range,
        text: code,
        forceMoveMarkers: true,
    };
    monacoEditor.executeEdits(code, [op]);
    monacoEditor.focus();
}


// 自动更新 options
watch(() => $props.options, (val) => {
    console.log('更新配置文件');
    if (val && monacoEditor) monacoEditor.updateOptions(val)
})

/** 自动更新 theme */
watch(() => $props.theme, async (themeName: string) => {

    await applyTheme(themeName as keyof AllTheme)

})
/** 自动更新 language */
watch(() => $props.language, async (language: string) => {
    changeLanguage(language)
})


const changeLanguage = (language: string) => {
    if (monacoEditor === null) return;
    window.monaco.editor.setModelLanguage(
        monacoEditor.getModel()!,
        language
    );
    console.log("语言更换为 " + language);

}
/* ====== 初始化操作 ===== */
/** 添加菜单的操作 */
const initAction: initPlugin = (editor, monaco) => {
    editor.addAction({
        id: "save", // 菜单项 id
        label: "保存", // 菜单项名称
        keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS], // 绑定快捷键，是 monacoEditor 自定义的对应关系
        contextMenuGroupId: "navigation", // 所属菜单的分组
        run: () => { saveValue() }, // 点击后执行的操作
    });
}

/** 绑定快捷键 */
const initKeybind: initPlugin = (editor, monaco) => {
    editor.addCommand(
        monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS,
        () => saveValue()
    );
}
/** 绑定相关的编辑器事件 */
const initEvent: initPlugin = (editor, monaco) => {
    // console.log(this.monacoEditor);
    editor.onDidChangeModelContent(() => {
        const code = editor!.getValue();
        codeCache.value = code
        $emit("input", code);
        $emit("update:model-value", code);

    });
}



onUnmounted(() => {
    monacoEditor && monacoEditor.dispose();
    monacoEditor = null;
})

defineExpose({
    saveValue,
    getEditor: () => monacoEditor,
})
</script>

   